/********************************************************************
	created:	2008/10/01
	created:	1:10:2008   20:06
	filename: 	h:\SimoneEngine\qianye\src\qylib\math\Vector4.h
	author:		Xiong Jiayu
	copyright:  
	purpose:	
*********************************************************************/
#pragma once

#ifndef __QYVECTOR4_H__
#define __QYVECTOR4_H__

/*
===========================================
struct Vector4
===========================================
*/
struct Vector4
{
public:
	float				x;
	float				y;
	float				z;
	float				w;

						Vector4( void );
						Vector4( const Vector4 &a );
						Vector4( const float x, const float y, const float z, const float w );

	void				Set( const float x, const float y, const float z, const float w );
	void				Zero( void );

	float				operator[]( const int index ) const;
	float &				operator[]( const int index );
	Vector4				operator-() const;
	float				operator*( const Vector4 &a ) const;
	Vector4				operator*( const float a ) const;
	Vector4				operator/( const float a ) const;
	Vector4				operator+( const Vector4 &a ) const;
	Vector4				operator-( const Vector4 &a ) const;
	Vector4 &			operator+=( const Vector4 &a );
	Vector4 &			operator-=( const Vector4 &a );
	Vector4 &			operator/=( const float a );
	Vector4 &			operator/=( const Vector4 &a );
	Vector4 &			operator*=( const float a );

	friend Vector4		operator*( const float a, const Vector4 &b );

	bool				Compare( const Vector4 &a ) const;
	bool				Compare( const Vector4 &a, const float epsilon ) const;
	bool				operator==( const Vector4 &a ) const;
	bool				operator!=( const Vector4 &a ) const;

	bool				IsZero( void ) const;

	float				Length( void ) const;
	float				LengthFast( void ) const;
	float				LengthSqr( void ) const;
	float				Normalize( void );
	float				NormalizeFast( void );
	
	const float *		ToFloatPtr( void ) const;
	float *				ToFloatPtr( void );
	
	void				Lerp( const Vector4 &v1, const Vector4 &v2, const float l );
};

//-----------------------------------------------------------------------
QY_INLINE Vector4::Vector4()
{
	x = 0; y = 0; z = 0; w = 0;
}

//-----------------------------------------------------------------------
QY_INLINE Vector4::Vector4( const float x, const float y, const float z, const float w )
{
	this->x = x; this->y = y; this->z = z; this->w = w;
}

//-----------------------------------------------------------------------
QY_INLINE Vector4::Vector4( const Vector4 &a )
{
	this->x = a.x; this->y = a.y; this->z = a.z; this->w = a.w;
}

//-----------------------------------------------------------------------
QY_INLINE void Vector4::Set( const float x, const float y, const float z, const float w )
{
	this->x = x; this->y = y; this->z = z; this->w = w;
}

//-----------------------------------------------------------------------
QY_INLINE void Vector4::Zero()
{
	this->x = 0; this->y = 0; this->z = 0; this->w = 0;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::operator[]( const int index ) const
{
	assert( index >= 0 && index < 4 );
	return (&x)[index];
}

//-----------------------------------------------------------------------
QY_INLINE float & Vector4::operator[]( const int index )
{
	assert( index >= 0 && index < 4 );
	return (&x)[index];
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 Vector4::operator-( void ) const
{
	return Vector4( -x, -y, -z, -w );
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 Vector4::operator-( const Vector4 &a ) const
{
	return Vector4( x - a.x, y - a.y, z - a.z, w - a.w );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::operator*( const Vector4 &a ) const
{
	return x * a.x + y * a.y + z * a.z + w * a.w;
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 Vector4::operator*( const float a  ) const
{
	return Vector4( x * a, y * a, z * a, w * a );
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 Vector4::operator/( const float a ) const
{
	float invA = 1.0f / a;
	return Vector4( x * invA, y * invA, z * invA, w * invA );
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 operator*( const float a, const Vector4 &b )
{
	return Vector4( b.x * a, b.y * a, b.z * a, b.w * a );
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 Vector4::operator+( const Vector4 &a ) const
{
	return Vector4( x + a.x, y + a.y, z + a.z, w + a.w );
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 & Vector4::operator+=( const Vector4 &a )
{
	x += a.x; y += a.y; z += a.z; w += a.w;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 & Vector4::operator/=( const Vector4 &a )
{
	x /= a.x; y /= a.y; z /= a.z; w /= a.w;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 & Vector4::operator/=( const float a )
{
	float invA = 1.0f / a;
	x *= invA; y *= invA; z *= invA; w *= invA;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 & Vector4::operator-=( const Vector4 &a )
{
	x -= a.x; y -= a.y; z -= a.z; w -= a.w;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE Vector4 & Vector4::operator*=( const float a )
{
	x *= a; y *= a; z *= a; w *= a;
	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector4::Compare( const Vector4 &a ) const
{
	return ( ( x == a.x ) && ( y == a.y ) && ( z == a.z ) && ( w == a.w ) );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector4::Compare( const Vector4 &a, const float epsilon ) const
{
	if ( fabs( x - a.x ) > epsilon )
		return false;

	if ( fabs( y - a.y ) > epsilon )
		return false;
	
	if ( fabs( z - a.z ) > epsilon )
		return false;

	if ( fabs( w - a.w ) > epsilon )
		return false;

	return true;
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector4::operator==( const Vector4 &a ) const
{
	return Compare( a );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector4::operator!=( const Vector4 & a ) const
{
	return !Compare( a );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector4::IsZero( void ) const
{
	return ( ( (*(const unsigned int *)&(x)) | (*(const unsigned int *)&(y)) | (*(const unsigned int *)&(z)) | (*(const unsigned int *)&(w)) ) & ~(1<<31) ) == 0;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::Length( void ) const
{
	return sqrt( x*x + y*y + z*z + w*w );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::LengthSqr( void ) const
{
	return x*x + y*y + z*z + w*w;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::LengthFast() const
{
	return qyRSqrt( x*x + y*y + z*z + w*w );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector4::Normalize()
{
	float sqrLength, invLength;

	sqrLength = x * x + y * y + z * z + w * w;

	if ( !sqrLength ) {		
		return 0.0f;
	}

	invLength = 1.0f / ( sqrtf( sqrLength ) );
	x *= invLength;
	y *= invLength;
	z *= invLength;
	w *= invLength;
	return invLength * sqrLength;
}




#endif
